# -*- coding: utf-8 -*-

"""使用PDF原始字典解析的页面对象。

除了在 :py:class:`~pdf2docx.page.RawPage` 中描述的基本结构外，
还包括一些新特性，例如章节、表格块等。
页面元素结构：

* :py:class:`~pdf2docx.page.Page` >> :py:class:`~pdf2docx.layout.Section` >> :py:class:`~pdf2docx.layout.Column`
    * :py:class:`~pdf2docx.layout.Blocks`
        * :py:class:`~pdf2docx.text.TextBlock` >>
          :py:class:`~pdf2docx.text.Line` >>
          :py:class:`~pdf2docx.text.TextSpan` / :py:class:`~pdf2docx.image.ImageSpan` >>
          :py:class:`~pdf2docx.text.Char`
        * :py:class:`~pdf2docx.table.TableBlock` >>
          :py:class:`~pdf2docx.table.Row` >>
          :py:class:`~pdf2docx.table.Cell`
            * :py:class:`~pdf2docx.layout.Blocks`
            * :py:class:`~pdf2docx.shape.Shapes`
    * :py:class:`~pdf2docx.shape.Shapes`
        * :py:class:`~pdf2docx.shape.Shape.Stroke`
        * :py:class:`~pdf2docx.shape.Shape.Fill`
        * :py:class:`~pdf2docx.shape.Shape.Hyperlink`

::

    {
        "id": 0, # 页面索引
        "width" : w,
        "height": h,
        "margin": [left, right, top, bottom],
        "sections": [{
            ... # 章节属性
        }, ...],
        "floats": [{
            ... # 浮动图片
        }, ...]
    }

"""

from docx.shared import Pt
from docx.enum.section import WD_SECTION
from ..common.Collection import BaseCollection
from ..common.share import debug_plot
from .BasePage import BasePage
from ..layout.Sections import Sections
from ..image.ImageBlock import ImageBlock


class Page(BasePage):
    """表示整个页面的对象，例如边距、部分。
    Page 类继承自 BasePage 类
    BasePage 类负责处理页面的基本几何属性（宽度、高度和边距）
    Page 类则添加了更多高级功能，如章节、浮动图像等。
    """

    def __init__(
        self,
        id: int = -1,
        skip_parsing: bool = True,
        width: float = 0.0,
        height: float = 0.0,
        header: str = None,
        footer: str = None,
        margin: tuple = None,
        sections: Sections = None,
        float_images: BaseCollection = None,
    ):
        """初始化页面布局。

        参数:
            id (int, optional): 页面索引。默认为 -1。
            skip_parsing (bool, optional): 如果为True则不解析页面。默认为True。
            width (float, optional): 页面宽度。默认为0.0。
            height (float, optional): 页面高度。默认为0.0。
            header (str, optional): 页眉。默认为None。
            footer (str, optional): 页脚。默认为None。
            margin (tuple, optional): 页面边距。默认为None。
            sections (Sections, optional): 页面内容。默认为None。
            float_images (BaseCollection, optional): 本页中的浮动图像。默认为None。
        """
        # 页面索引
        self.id = id
        self.skip_parsing = skip_parsing

        # 页面大小和边距，super()调用父类，为BasePage的__init__方法
        # 将当前 Page 实例的宽度（width）、高度（height）和边距（margin）属性的初始化工作委托给父类 BasePage 处理
        super().__init__(width=width, height=height, margin=margin)

        # 流结构:
        # Section -> Column -> Blocks -> TextBlock/TableBlock
        # TableBlock -> Row -> Cell -> Blocks
        self.sections = sections or Sections(parent=self)

        # 页眉，页脚
        self.header = header or ""
        self.footer = footer or ""

        # 浮动图像是页面下的单独节点
        self.float_images = float_images or BaseCollection()

        self._finalized = False

    @property
    def finalized(self):
        return self._finalized

    def store(self):
        """以字典格式存储解析后的布局。"""
        res = {
            "id": self.id,
            "width": self.width,
            "height": self.height,
            "margin": self.margin,
            "sections": self.sections.store(),
            "header": self.header,
            "footer": self.footer,
            "floats": self.float_images.store(),
        }
        return res

    def restore(self, data: dict):
        """从解析结果恢复布局。"""
        # 页面ID
        self.id = data.get("id", -1)

        # 页面宽度/高度
        self.width = data.get("width", 0.0)
        self.height = data.get("height", 0.0)
        self.margin = data.get("margin", (0,) * 4)

        # 解析布局
        self.sections.restore(data.get("sections", []))
        self.header = data.get("header", "")
        self.footer = data.get("footer", "")

        # 浮动图像
        self._restore_float_images(data.get("floats", []))

        # 假设恢复时布局已完成；否则，在此方法外
        # 显式设置为False。
        self._finalized = True

        return self

    @debug_plot("最终布局")
    def parse(self, **settings):
        """解析页面布局。"""
        self.sections.parse(**settings)
        self._finalized = True
        return self.sections  # 用于调试绘图

    def extract_tables(self, **settings):
        """从表格中提取内容（仅顶层布局）。

        .. note::
            在运行此方法之前，页面布局必须从源页面解析
            或从解析数据恢复。
        """
        # 表格块
        collections = []
        for section in self.sections:
            for column in section:
                if settings["extract_stream_table"]:
                    collections.extend(column.blocks.table_blocks)
                else:
                    collections.extend(column.blocks.lattice_table_blocks)

        # 检查表格
        tables = []  # type: list[ list[list[str]] ]
        for table_block in collections:
            tables.append(table_block.text)

        return tables

    def make_docx(self, doc):
        """设置页面大小、边距并创建页面。

        .. note::
            在运行此方法之前，页面布局必须从源页面解析
            或从解析数据恢复。

        参数:
            doc (Document): ``python-docx`` 文档对象
        """
        # 新页面
        if doc.paragraphs:
            section = doc.add_section(WD_SECTION.NEW_PAGE)
        else:
            section = doc.sections[0]  # 打开docx时存在默认节

        # 页面大小
        section.page_width = Pt(self.width)
        section.page_height = Pt(self.height)

        # 页面边距
        left, right, top, bottom = self.margin
        section.left_margin = Pt(left)
        section.right_margin = Pt(right)
        section.top_margin = Pt(top)
        section.bottom_margin = Pt(bottom)

        # 创建流布局: 节
        self.sections.make_docx(doc)

    def _restore_float_images(self, raws: list):
        """恢复浮动图像。"""
        self.float_images.reset()
        for raw in raws:
            image = ImageBlock(raw)
            image.set_float_image_block()
            self.float_images.append(image)
